package com.pansoft.openplanet.account.util;

import com.efounder.constant.EnvironmentVariable;
import com.pansoft.openplanet.account.model.BchGeneratorBean;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.constant.IPAssetsConstant;
import com.pansoft.openplanet.util.BchMnemonicUtils;
import com.pansoft.openplanet.util.BchNetParamUtil;
import com.pansoft.openplanet.util.TCAccountManager;
import com.utilcode.util.LogUtils;
import com.utilcode.util.TimeUtils;

import org.bitcoincashj.core.Address;
import org.bitcoincashj.core.CashAddressFactory;
import org.bitcoincashj.core.ECKey;
import org.bitcoincashj.crypto.DeterministicKey;
import org.bitcoincashj.wallet.DeterministicSeed;
import org.bitcoincashj.wallet.Wallet;
import org.web3j.utils.Numeric;

import java.io.File;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

import static com.efounder.frame.utils.Constants.CHAT_USER_ID;

/**
 * BCH比特币现金账户相关
 * @author will
 */
public class BchAccountGenerator {

    private static final String TAG = "BchAccountGenerator";


    /**
     * todo 异步方法创建账户
     *
     * @param keyStoreDirPath keystore文件存放目录
     * @return
     * @throws Exception
     */
    public static Disposable createBtcAccountAsync(final String keyStoreDirPath, final GeneratorListener generatorListener) {
        if (keyStoreDirPath == null) {
            if (generatorListener != null) {
                generatorListener.generatorFail();
            }
            return null;
        }
        //如果目录不存在，创建目录
        File file = new File(keyStoreDirPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }

        Disposable disposable = Observable.create(new ObservableOnSubscribe<BchGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<BchGeneratorBean> emitter) throws Exception {
                BchGeneratorBean bchBean = createBtcAccountSync(keyStoreDirPath);
                //加密助记词
                String secretMnemonic = TCAccountManager.encryptByMainPrivKey(bchBean.getMnemonic());
                bchBean.setSecretMnemonic(secretMnemonic);
                emitter.onNext(bchBean);
                emitter.onComplete();
            }
        })        // 在io线程生成walletfile的进行操作
                .subscribeOn(Schedulers.io())
                // 在主线程处理walletfile保存
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<BchGeneratorBean>() {
                    @Override
                    public void accept(@NonNull BchGeneratorBean ethBean) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorSuccess(ethBean);
                        }

                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * todo 同步方法创建 账户
     *
     * @param keyStoreDirPath keystore 文件存放目录
     * @return
     * @throws Exception
     */
    public static BchGeneratorBean createBtcAccountSync(String keyStoreDirPath) throws Exception {

        //生成助记词
        DeterministicSeed ds = BchMnemonicUtils.generateMnemonic("");
        List<String> mnemonicList = ds.getMnemonicCode();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < mnemonicList.size(); i++) {
            stringBuffer.append(mnemonicList.get(i)).append(" ");
        }
        String mnemonic = stringBuffer.substring(0, stringBuffer.length() - 1);

        //生成eckey
        ECKey ecKey = BchMnemonicUtils.generateECKey(ds);
        //解析公钥
        String publickey = Numeric.toHexStringNoPrefixZeroPadded(new BigInteger(ecKey.getPubKey()), 66);
        //解析私钥
        String privateKey = ecKey.getPrivateKeyEncoded(BchNetParamUtil.getBtcNetParams()).toString();
        //解析地址
        // String btcAddress = ecKey.(TestNet3Params.get()).toString();
        Address myAddress = ecKey.toAddress(BchNetParamUtil.getBtcNetParams());
        Address bchAddress = CashAddressFactory.create().getFromBase58(BchNetParamUtil.getBtcNetParams(), myAddress.toBase58());
//        Address myAddress = ecKey.toAddress(BchNetParamUtil.getBtcNetParams());
        System.out.println("bchAddress:" + bchAddress);


        String btcAddress = bchAddress.toString();

//        System.out.println(privateKey);
//        System.out.println(publickey);
//        System.out.println("eckey 生成的btcAddress:" + btcAddress);

        //保存文件
        Wallet wallet = Wallet.fromSeed(BchNetParamUtil.getBtcNetParams(), ds);
        //System.out.println("wallet 生成的btcAddress:" + wallet.currentReceiveAddress());
        //文件名
        SimpleDateFormat dateFormat = new SimpleDateFormat("'BCH--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
        String fileName = dateFormat.format(new Date()) + btcAddress + ".wallet";
        File keyStoreFile = new File(keyStoreDirPath, fileName);

        wallet.saveToFile(keyStoreFile);

        com.utilcode.util.LogUtils.i(privateKey, publickey, "eckey 生成的btcAddress:" + btcAddress,
                "wallet 生成的btcAddress:" + wallet.currentReceiveAddress());

        BchGeneratorBean bchBean = new BchGeneratorBean();
        bchBean.setWalletAddress(btcAddress);
        bchBean.setPrivateKey(privateKey);
        bchBean.setPublicKey(publickey);
        bchBean.setKeyStoreFilePath(keyStoreFile.getAbsolutePath());
        bchBean.setMnemonic(mnemonic);
        bchBean.setMnemonicList(mnemonicList);

        return bchBean;
    }

    /**
     * todo 使用助记词恢复钱包
     *
     * @param keyStoredirPath   keystore 路径
     * @param mnemoric          助记词（" "分割）
     * @param generatorListener
     * @return
     */
    public static Disposable recoverBchAccountByMnemoric(final String keyStoredirPath, final String mnemoric,
                                                         final GeneratorListener generatorListener) {
        //如果目录不存在，创建目录
        File file = new File(keyStoredirPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        Disposable disposable = Observable.create(new ObservableOnSubscribe<BchGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<BchGeneratorBean> emitter) throws Exception {
                //助记词恢复
                BchGeneratorBean ethBean = BchMnemonicUtils.restoreByMnemonic(mnemoric, "");
                //加密助记词
                String secretMnemonic = TCAccountManager.encryptByMainPrivKey(mnemoric);
                ethBean.setSecretMnemonic(secretMnemonic);
                emitter.onNext(ethBean);
                emitter.onComplete();
            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<BchGeneratorBean>() {
                    @Override
                    public void accept(BchGeneratorBean btcBean) throws Exception {
                        //文件名
                        SimpleDateFormat dateFormat = new SimpleDateFormat("'BCH--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
                        String fileName = dateFormat.format(new Date()) + btcBean.getWalletAddress() + ".wallet";
                        File keyStoreFile = new File(keyStoredirPath, fileName);

                        btcBean.getWallet().saveToFile(keyStoreFile);
                        btcBean.setKeyStoreFilePath(keyStoreFile.getAbsolutePath());
                        generatorListener.generatorSuccess(btcBean);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * 同步方法恢复bch账户
     * @param keyStoredirPath
     * @param mnemoric
     * @return
     * @throws Exception
     */
    public static Account recoverBchAccountSync(final String keyStoredirPath, final String mnemoric,
                                                String accountName, String accountAvatar) throws Exception{
        //如果目录不存在，创建目录
        File file = new File(keyStoredirPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        //助记词恢复
        BchGeneratorBean btcBean = BchMnemonicUtils.restoreByMnemonic(mnemoric, "");
        //加密助记词
        String secretMnemonic = TCAccountManager.encryptByMainPrivKey(mnemoric);
        btcBean.setSecretMnemonic(secretMnemonic);
        //文件名
        SimpleDateFormat dateFormat = new SimpleDateFormat("'BCH--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
        String fileName = dateFormat.format(new Date()) + btcBean.getWalletAddress() + ".wallet";
        File keyStoreFile = new File(keyStoredirPath, fileName);

        btcBean.getWallet().saveToFile(keyStoreFile);
        btcBean.setKeyStoreFilePath(keyStoreFile.getAbsolutePath());

        Account btcAccount = new Account();
        btcAccount.setAddress(btcBean.getWalletAddress());
        btcAccount.setAccountAvatar(accountAvatar);
        btcAccount.setAcccountName(accountName);
        btcAccount.setFileName(btcBean.getKeyStoreFilePath());
        btcAccount.setImUserId(EnvironmentVariable.getProperty(CHAT_USER_ID));
        btcAccount.setPublicKey(btcBean.getPublicKey());
        btcAccount.setSecretMnemonic(btcBean.getSecretMnemonic());
        btcAccount.setSecretPrivateKey(TCAccountManager.encryptByMainPrivKey(btcBean.getPrivateKey()));
        btcAccount.setMainAccoutAddress(EnvironmentVariable.getProperty("tc_ethAddress", ""));
        btcAccount.setBlockChainName(IPAssetsConstant.ChainEnum.BCH.chainName);
        btcAccount.setCreateTime(TimeUtils.getNowString());
        btcAccount.setEnable(false);

        return btcAccount;
    }

    /**
     * todo 从本地文件加载钱包
     *
     * @param filePath          文件路径
     * @param generatorListener
     * @return
     */
    public static Disposable loadWalletFromFile(final String filePath,
                                                final GeneratorListener generatorListener) {
        Disposable disposable = Observable.create(new ObservableOnSubscribe<BchGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<BchGeneratorBean> emitter) throws Exception {

                Wallet wallet = Wallet.loadFromFile(new File(filePath));
                DeterministicKey deterministicKey = wallet.currentReceiveKey();
                BigInteger privKeyBTC = deterministicKey.getPrivKey();
                ECKey ecKey = ECKey.fromPrivate(privKeyBTC);
                String publickey = Numeric.toHexStringNoPrefixZeroPadded(new BigInteger(ecKey.getPubKey()), 66);
                //私钥
                String privateKey = ecKey.getPrivateKeyEncoded(BchNetParamUtil.getBtcNetParams()).toString();
                //地址
                String btcAddress = wallet.currentReceiveAddress().toString();

                LogUtils.i(publickey, privateKey, btcAddress, wallet.toString());

                BchGeneratorBean bchBean = new BchGeneratorBean();
                bchBean.setWalletAddress(btcAddress);
                bchBean.setPrivateKey(privateKey);
                bchBean.setPublicKey(publickey);
                bchBean.setWallet(wallet);
                emitter.onNext(bchBean);
                emitter.onComplete();
            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<BchGeneratorBean>() {
                    @Override
                    public void accept(BchGeneratorBean btcBean) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorSuccess(btcBean);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

//    /**
//     * todo 使用私钥恢复钱包
//     *
//     * @param keyStoredirPath   keystore 路径
//     * @param key               私钥
//     * @param generatorListener
//     * @return
//     */
//    public static Disposable recoverAccountByPrivateKey(final String keyStoredirPath, String key,
//                                                        final GeneratorListener generatorListener) {
//        BigInteger privateKey = null;
//        try {
//            if (key.length() > 2) {
//                if ("0x".equals(key.substring(0, 2).toLowerCase())) {
//                    //去掉0X
//                    key = key.substring(2, key.length());
//                    // key = String16Utils.str2HexStr(key);
//                    privateKey = new BigInteger(key, 16);
//                } else {
//                    privateKey = new BigInteger(key, 16);
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            if (generatorListener != null) {
//                generatorListener.generatorFail();
//            }
//        }
//
//        final BigInteger finalPrivateKey = privateKey;
//        Disposable disposable = Observable.create(new ObservableOnSubscribe<BtcBean>() {
//            @Override
//            public void subscribe(ObservableEmitter<BtcBean> emitter) throws Exception {
//                ECKeyPair ecKeyPair = ECKeyPair.create(finalPrivateKey);
//                WalletFile walletFile = Wallet.createLight("", ecKeyPair);
//
//                BtcBean ethBean = new BtcBean.Builder()
//                        .walletFile(walletFile)
//                        .ecKeyPair(ecKeyPair)
//                        .ethAddress("0x" + walletFile.getAddress())
//                        .build();
//                emitter.onNext(ethBean);
//                emitter.onComplete();
//
//            }
//
//        }).subscribeOn(Schedulers.io())
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Consumer<BtcBean>() {
//                    @Override
//                    public void accept(BtcBean ethBean) throws Exception {
//                        SimpleDateFormat dateFormat = new SimpleDateFormat("'UTC--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
//                        String fileName = dateFormat.format(new Date()) + ethBean.getWalletFile().getAddress() + ".json";
//                        File destination = new File(keyStoredirPath, fileName);
//                        ObjectMapper objectMapper = new ObjectMapper();
//                        //写入文件
//                        objectMapper.writeValue(destination, ethBean.getWalletFile());
//                        File realFile = new File(keyStoredirPath + File.separator + fileName);
//                        ethBean.setKeyStoreFilePath(realFile.getAbsolutePath());
//                        if (!realFile.exists()) {
//                            FileDeleteUtil.delete(realFile);
//                            if (generatorListener != null) {
//                                generatorListener.generatorFail();
//                            }
//                            return;
//                        } else {
//                            generatorListener.generatorSuccess(ethBean);
//                        }
//                    }
//                }, new Consumer<Throwable>() {
//                    @Override
//                    public void accept(Throwable throwable) throws Exception {
//                        if (generatorListener != null) {
//                            generatorListener.generatorFail();
//                        }
//                    }
//                });
//        return disposable;
//
//    }

    /**
     * 钱包创建恢复的回调
     */
    public interface GeneratorListener {
        //成功
        void generatorSuccess(BchGeneratorBean ethBean);

        //失败
        void generatorFail();
    }
}
